import { IEditorsState, IEvent, IFile, IEditor } from "./model";
import { getExtName, getLang, writeFile, loadFile } from "../utils/file-util";

let count = 0;

function init (): IEditorsState {
  return {
    editors: [],
    activeId: null,
  };
}

function onOpen (e: IEvent, s: IEditorsState): IEditorsState {
  const file: IFile = e.data;
  const existsEditor = s.editors.find(o => o.filePath == file.filePath);
  if (existsEditor) {
    return {
      ...s,
      activeId: existsEditor.id,
    }
  } else {
    const extName = getExtName(file.name);
    const content = loadFile(file.filePath);
    const editor: IEditor = {
      id: `${Date.now()}__${count++}`,
      filePath: file.filePath,
      originContent: content,
      extName,
      lang: getLang(extName),
      fileName: file.name,
      content: content,
      cursor: {
        rowNo: 0,
        colNo: 0,
      },
      selected: 0,
    };
    return {
      ...s,
      editors: [ ...s.editors, editor ],
      activeId: editor.id,
    };
  }
}

function onActive (e: IEvent, s: IEditorsState): IEditorsState {
  const id: string = e.data;
  const editor = s.editors.find(o => o.id == id);
  if (editor) {
    return {
      ...s,
      activeId: id,
    }
  } else {
    s;
  }
}

function onSave (e: IEvent, s: IEditorsState): IEditorsState {
  const id: string = e.data;
  const editor = s.editors.find(o => o.id == id);
  if (editor.content != editor.originContent) {
    writeFile(editor.filePath, editor.content);
    const newEditor: IEditor = {
      ...editor,
      originContent: editor.content,
    };
    return {
      ...s,
      editors: s.editors.map(o => o == editor ? newEditor : o)
    };
  }
  return s;
}

function onClose (e: IEvent, s: IEditorsState): IEditorsState {
  const id: string = e.data;
  if (s.activeId == id) {
    const index = s.editors.findIndex(o => o.id == id);
    const nextActiveEditor = s.editors[index + 1] || s.editors[index - 1] || null;
    const activeId = nextActiveEditor?.id || null;
    return {
      ...s,
      editors: s.editors.filter(o => o.id != id),
      activeId,
    };
  } else {
    return {
      ...s,
      editors: s.editors.filter(o => o.id != id),
    };
  }
}

function onChanged (e: IEvent, s: IEditorsState): IEditorsState{
  const id: string = e.data.id;
  const content: string = e.data.content;
  const editor = s.editors.find(o => o.id == id);
  if (editor) {
    const newEditor: IEditor = {
      ...editor,
      content,
    };
    return {
      ...s,
      editors: s.editors.map(o => o == editor ? newEditor : o)
    };
  } else {
    return s;
  }
}


function onCursorChanged (e: IEvent, s: IEditorsState): IEditorsState{
  const id: string = e.data.id;
  const rowNo: number = e.data.rowNo;
  const colNo: number = e.data.colNo;
  const selected: number = e.data.selected;
  const editor = s.editors.find(o => o.id == id);
  if (editor) {
    const newEditor: IEditor = {
      ...editor,
      cursor: {
        rowNo,
        colNo,
      },
      selected,
    };
    return {
      ...s,
      editors: s.editors.map(o => o == editor ? newEditor : o)
    };
  } else {
    return s;
  }
}

export function dispatch (e: IEvent, s: IEditorsState): IEditorsState {
  if (e.type == 'app.init') {
    return init();
  } if (e.type == 'editor.open') {
    return onOpen(e, s);
  } if (e.type == 'editor.active') {
    return onActive(e, s);
  } if (e.type == 'editor.save') {
    return onSave(e, s);
  } if (e.type == 'editor.close') {
    return onClose(e, s);
  } if (e.type == 'editor.changed') {
    return onChanged(e, s);
  } if (e.type == 'editor.cursorChanged') {
    return onCursorChanged(e, s);
  } else {
    return s;
  }
}